#include "predictor21264.h"

/*
 * Helper function
 * Returns 2^n - 1 (an n bit intger with all bits set to 1)
 */
unsigned ones(unsigned n)
{
    unsigned i = 0;
    for (n; n > 0; n--)
    {
        i = i << 1;
        i++;
    }
    return i;
}

void init_predictor ()
{
    for (int i = 0; i < LHT_SIZE; i++)
        LHT[i] = 0;
    for (int i = 0; i < LPT_SIZE; i++)
        LPT[i] = 0;
    GHT = 0;
    for (int i = 0; i < GPT_SIZE; i++)
        GPT[i] = 0;
    for (int i = 0; i < CPT_SIZE; i++)
        CPT[i] = 0;
}

bool make_prediction (unsigned int pc)
{
    unsigned index = pc & ones(10);
    if (CPT[GHT]  < 2)
        return LPT[LHT[index]] > 3;
    return GPT[GHT] > 1;
}

void train_predictor (unsigned int pc, bool outcome)
{
    unsigned index = pc & ones(10);
    /* update CPT */
    bool global_pred = GPT[GHT] > 1;
    bool local_pred = LPT[LHT[index]] > 3;
    if (global_pred != local_pred)
    {
        if (local_pred != outcome && CPT[GHT] < 3)
            CPT[GHT]++;
        else if (global_pred != outcome && CPT[GHT] > 0)
            CPT[GHT]--;
    }

    int lh = LHT[index];
    int gh = GHT;
    
    /* update LHT, LPT, GHT, & GPT */
    LHT[index] = LHT[index] << 1;
    GHT = GHT << 1;
    if (outcome)
    {
        if (LPT[lh] < 7)
            LPT[lh]++;
        
        LHT[index]++;
        GHT++;

        if (GPT[gh] < 3)
            GPT[gh]++;
    }
    else
    {
        if (LPT[lh] > 0)
            LPT[lh]--;
        if (GPT[gh] > 0)
            GPT[gh]--;
    }

    LHT[index] &= ones(10);
    GHT &= ones(12);
}
